import { ComponentFixture, fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing';
import { ChangeDetectionStrategy, Component, Input, ViewChild } from '@angular/core';
import { DatatableModule } from './datatable.module';
import { CommonModule } from '@angular/common';
import { DatatableComponent } from './datatable.component';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';

@Component({
  template: `
    <lv-datatable
      lvSelectionMode="multiple"
      [lvSelection]="selection"
      (lvSelectionChange)="selectChange($event)"
      [lvCompareWith]="compareWith"
      [lvData]="lvData"
      #lvTable
    >
      <thead>
        <tr>
          <th style="width: 40px"></th>
          <th style="width: 40px"></th>
          <th>Name</th>
          <th>Age</th>
        </tr>
      </thead>
      <tbody>
        <ng-container *ngFor="let item of lvTable.renderData">
          <tr>
            <td
              lvShowCheckbox
              lvCheckboxTip="tipTest"
              [lvRowData]="item"
              [lvDisabled]="item.lvDisabled"
              (lvCheckChange)="checkOneChange()"
            ></td>
            <td
              [lvShowUnfold]="lvShowUnfold"
              (lvUnfoldChange)="unfoldChange()"
              [(lvUnfold)]="item.expand"
              [lvUnfoldToggleIcon]="lvUnfoldToggleIcon"
            ></td>
            <td [lvAlign]="lvAlign">{{ item.name }}</td>
            <td [lvAlign]="lvAlign">{{ item.age }}</td>
          </tr>
          <tr *ngIf="item.expand" lvInnerUnfold>
            <td colspan="4" lvInnerUnfold>
              <div class="expand_text">expand_text</div>
            </td>
          </tr>
        </ng-container>
      </tbody>
    </lv-datatable>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
class TestTdComponent {
  @Input() lvData = [
    { name: 'user1', age: 10 },
    { name: 'user2', age: 12, lvDisabled: true },
    { name: 'user3', age: 11 },
  ];
  @Input() lvAlign = 'left';
  @Input() lvShowUnfold = false;
  @Input() lvUnfoldToggleIcon = 'lv-icon-triangle-down';

  @ViewChild('lvTable', { static: true }) tableComponent: DatatableComponent;

  compareWith;
  selection = [];
  checkOneChange() {}
  selectChange() {}
  unfoldChange() {}
}
describe('TdComponent', () => {
  beforeEach(
    waitForAsync(() => {
      TestBed.configureTestingModule({
        declarations: [TestTdComponent],
        imports: [DatatableModule, CommonModule, NoopAnimationsModule],
        teardown: { destroyAfterEach: true },
      }).compileComponents();
    })
  );
  describe('render', () => {
    let component: TestTdComponent;
    let fixture: ComponentFixture<TestTdComponent>;
    const renderComp = fakeAsync(para => {
      for (const [key, value] of Object.entries(para)) {
        component[key] = value;
      }
      fixture.detectChanges();
      tick(500);
      fixture.detectChanges();
      expect(fixture).toMatchSnapshot();
      tick(1500);
    });

    beforeEach(fakeAsync(() => {
      fixture = TestBed.createComponent(TestTdComponent);
      component = fixture.componentInstance;
      fixture.detectChanges();
      tick(500);
    }));

    // 不同对齐方式渲染
    it('with lvAlign', () => {
      renderComp({ lvAlign: 'center' });
    });

    it('with lvAlign', () => {
      renderComp({ lvAlign: 'right' });
    });

    // 是否展开详情icon渲染及展开详情切换icon渲染
    it('with lvShowUnfold and lvUnfoldToggleIcon', () => {
      renderComp({ lvShowUnfold: true, lvUnfoldToggleIcon: { true: 'lv-icon-tree-unfold', false: 'lv-icon-tree-fold' } });
    });
  });

  describe('work', () => {
    let component: TestTdComponent;
    let fixture: ComponentFixture<TestTdComponent>;

    beforeEach(fakeAsync(() => {
      fixture = TestBed.createComponent(TestTdComponent);
      component = fixture.componentInstance;
      jest.spyOn(component, 'checkOneChange');
      jest.spyOn(component, 'selectChange');
      jest.spyOn(component, 'unfoldChange');
    }));

    // lvSelection默认绑定生效
    it('with lvSelection', fakeAsync(() => {
      component.selection = [component.lvData[2]];
      fixture.detectChanges();
      tick(500);
      fixture.detectChanges();
      tick(500);
      fixture.detectChanges();
      expect(fixture.nativeElement.querySelector('.lv-icon-checked')).not.toBeNull();
    }));

    // 选中比较方式生效，lvCompareWith（lvCompareWith返回值不在optionItem中）
    it('with lvCompareWith', fakeAsync(() => {
      // compareWith传入非法key不报错
      component.compareWith = 'test';
      fixture.detectChanges();
      tick(500);

      // 使用name作为比较方式
      component.compareWith = 'name';
      fixture.detectChanges();
      tick(500);
      fixture.detectChanges();
      const checkbox = fixture.nativeElement.querySelectorAll('.lv-checkbase');
      checkbox[0].dispatchEvent(new Event('click'));
      tick(500);
      fixture.detectChanges();
      tick(500);
      fixture.detectChanges();
      // 点击一次，选中两项
      expect(fixture.nativeElement.querySelector('.lv-icon-checked')).not.toBeNull();
    }));

    // 复选框可多选，选中会触发lvCheckChange和表格的lvSelectionChange回调
    it('trigger lvCheckChange when selected', fakeAsync(() => {
      fixture.detectChanges();
      tick(500);
      fixture.detectChanges();
      const checkbox = fixture.nativeElement.querySelectorAll('.lv-checkbase');
      checkbox[0].dispatchEvent(new Event('click'));
      tick(500);
      fixture.detectChanges();
      expect(component.selectChange).toBeCalledTimes(1);
      expect(component.checkOneChange).toBeCalledTimes(1);

      checkbox[2].dispatchEvent(new Event('click'));
      tick(500);
      fixture.detectChanges();
      expect(component.selectChange).toBeCalledTimes(2);
      expect(component.checkOneChange).toBeCalledTimes(2);
      expect(fixture).toMatchSnapshot();
    }));

    // 复选框disabled状态下无法点击选中
    it('when checkbox disabled', fakeAsync(() => {
      fixture.detectChanges();
      tick(500);
      fixture.detectChanges();
      const checkbox = fixture.nativeElement.querySelectorAll('.lv-checkbase');
      checkbox[1].dispatchEvent(new Event('click')); // 第二行状态为disabled
      tick(500);
      fixture.detectChanges();
      tick(500);
      fixture.detectChanges();
      expect(component.selectChange).toBeCalledTimes(0);
      expect(component.checkOneChange).toBeCalledTimes(0);
      expect(fixture.nativeElement.querySelector('.lv-icon-checked')).toBeNull();
    }));

    // 点击展开详情，表格下展，并触发lvUnfoldChange回调
    it('trigger lvUnfoldChange when Unfold', fakeAsync(() => {
      component.lvShowUnfold = true;
      fixture.detectChanges();
      tick(500);
      fixture.detectChanges();

      expect(fixture.nativeElement.querySelector('.expand_text')).toBeNull();
      const toggle = fixture.nativeElement.querySelectorAll('.lv-table-toggle-unfold');

      toggle[0].dispatchEvent(new Event('click'));
      tick(500);
      fixture.detectChanges();
      expect(fixture.nativeElement.querySelector('.expand_text').textContent).toContain('expand_text');
      expect(component.unfoldChange).toBeCalledTimes(1);
    }));

    // 复选框悬浮提示信息，快照
    it('lvCheckboxTip show correctly when hover', fakeAsync(() => {
      fixture.detectChanges();
      tick(500);
      fixture.detectChanges();
      const checkbox = fixture.nativeElement.querySelectorAll('.lv-checkbase');
      checkbox[0].dispatchEvent(new MouseEvent('mouseenter', { bubbles: true }));
      tick(500);
      fixture.detectChanges();

      expect(document.querySelector('.lv-tooltip-inner').textContent).toContain('tipTest');
    }));
  });
});
